package camid.distribution.lifecycle.perrequest;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Executors;

import camid.distribution.activeobject.ObjectRegistry;
import camid.distribution.activeobject.ObjectScheduler;
import camid.distribution.events.FutureNotificator;
import camid.distribution.lifecycle.AbstractLifecycleManager;
import camid.distribution.lifecycle.DefaultEntityFactory;
import camid.test.testobjects.Calculator;

public class PerRequestLifecycleManager extends AbstractLifecycleManager {
	
	private ObjectRegistry registry;
	
	private Map<Class<?>, String> definitionPool;
	
	private Map<String, String> referencePool;
	
	public PerRequestLifecycleManager(ObjectRegistry objectRegistry) 
	{
		super(objectRegistry);
		registry = objectRegistry;
		definitionPool = Collections.synchronizedMap(new HashMap<Class<?>, String> ());
		referencePool = Collections.synchronizedMap(new HashMap<String, String> ());
	}

	public PerRequestLifecycleManager(ObjectRegistry objectRegistry,
			FutureNotificator notificator) 
	{
		super(objectRegistry, notificator);
		registry = objectRegistry;
		definitionPool = Collections.synchronizedMap(new HashMap<Class<?>, String> ());
		referencePool = Collections.synchronizedMap(new HashMap<String, String> ());
	}

	@Override
	public void shutdown() 
	{
		this.registry.shutdown();	
	}

	@Override
	public ObjectScheduler newObject(String objectId, Class<?> entityClass,
			DefaultEntityFactory defaultObjectBuilder)
			throws InstantiationException, IllegalAccessException {
		
		ObjectScheduler scheduler = null;
		if(definitionPool.containsKey(entityClass))
		{
			// Contains object in pool
			String referenceId = definitionPool.get(entityClass);
			referencePool.put(objectId, referenceId);
			scheduler = registry.get(referenceId);
		}
		else
		{
			// Does not contain object in pool
			Object entity = defaultObjectBuilder.newEntity(entityClass);
			String referenceId = UUID.randomUUID().toString();
			scheduler = new ObjectScheduler(referenceId, entity, Executors.newCachedThreadPool());
			definitionPool.put(entity.getClass(), referenceId);
			referencePool.put(objectId, referenceId);
			registry.add(scheduler);
		}
		notifyObjectCreation(objectId, entityClass);
		return scheduler;
	}

	@Override
	public ObjectScheduler destroyObject(String objectId) 
	{
		ObjectScheduler scheduler = null;
		if(referencePool.containsKey(objectId))
		{
			String referenceId = referencePool.get(objectId);
			scheduler = registry.get(referenceId);
			referencePool.remove(objectId);
		}
		notifyObjectDestruction(objectId);
		return scheduler;
	}

	@Override
	public boolean hasObject(String objectId) {
		if( referencePool.containsKey(objectId) )
		{
			return true;
		}
		return false;
	}

	@Override
	public ObjectScheduler getObject(String objectId) {
		
		ObjectScheduler scheduler = null;
		if(referencePool.containsKey(objectId))
		{
			String referenceId = referencePool.get(objectId);
			scheduler = registry.get(referenceId);
		}
		
		return scheduler;
	}

	@Override
	public ObjectScheduler insertObject(String objectId, Object entity) throws InstantiationException, IllegalAccessException {
		
		ObjectScheduler scheduler = newObject(objectId, entity.getClass(), new DefaultEntityFactory());
		notifyObjectCreation(objectId, entity.getClass());
		return scheduler;
		
	}

}
